--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit ca72ead6c02cd8ed028840f846b7f9350762ef6e
Parents : 82f58ac
Author : Mark Qvist <bc7291552be7a58f361522990465165c>
Signature : T66BB85Valid, signed by author
Date : 2026-07-20T18:46:33+02:00
Added map providers
Changes
3 files changed, 110 insertions(+), 10 deletions(-)
Diff
diff --git a/sbapp/mapview/source.py b/sbapp/mapview/source.py
index 98d98591..488285c0 100644
--- a/sbapp/mapview/source.py
+++ b/sbapp/mapview/source.py
@@ -13,24 +13,30 @@ from mapview.utils import clamp
class MapSource:
mt_key = ""
+ st_key = ""
attribution_osm = "© OpenStreetMap contributors"
attribution_ve = "© VirtualEarth"
attribution_mt = "© MapTiler © OpenStreetMap contributors"
+ attribution_st = "© Stadia © OpenMapTiles © OpenStreetMap contributors"
custom_1_url = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
providers = {}
@staticmethod
def update_providers():
MapSource.providers = {
- "osm": ("OpenStreetMap", 0, 0, 19, "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", MapSource.attribution_osm, 256),
- "mt_topo": ("Topographic", 0, 0, 19, "https://api.maptiler.com/maps/topo-v4/256/{z}/{x}/{y}.png?key="+MapSource.mt_key, MapSource.attribution_mt, 256),
- "mt_outdoor": ("Outdoor", 0, 0, 19, "https://api.maptiler.com/maps/outdoor-v4/256/{z}/{x}/{y}.png?key="+MapSource.mt_key, MapSource.attribution_mt, 256),
- "mt_hybrid": ("Hybrid", 0, 0, 19, "https://api.maptiler.com/maps/hybrid-v4/256/{z}/{x}/{y}.jpg?key="+MapSource.mt_key, MapSource.attribution_mt, 256),
- "virtualearth": ("VirtualEarth", 0, 0, 19, "http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g=1", MapSource.attribution_ve, 256),
- "opentopo": ("OpenTopo", 0, 0, 19, "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png", MapSource.attribution_osm, 256),
- "atlas": ("Atlas", 0, 0, 19, "https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}", "© Esri", 256),
- "googlemaps": ("Google Maps", 0, 0, 19, "https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}", "© Google", 256),
- "custom_1": ("Custom 1", 0, 0, 19, MapSource.custom_1_url, "Custom Map", 256),
+ "osm": ("OpenStreetMap", 0, 0, 19, "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", MapSource.attribution_osm, 256),
+ "mt_topo": ("Topographic", 0, 0, 19, "https://api.maptiler.com/maps/topo-v4/256/{z}/{x}/{y}.png?key="+MapSource.mt_key, MapSource.attribution_mt, 256),
+ "mt_outdoor": ("Outdoor", 0, 0, 19, "https://api.maptiler.com/maps/outdoor-v4/256/{z}/{x}/{y}.png?key="+MapSource.mt_key, MapSource.attribution_mt, 256),
+ "mt_hybrid": ("Hybrid", 0, 0, 19, "https://api.maptiler.com/maps/hybrid-v4/256/{z}/{x}/{y}.jpg?key="+MapSource.mt_key, MapSource.attribution_mt, 256),
+ "virtualearth": ("VirtualEarth", 0, 0, 19, "http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g=1", MapSource.attribution_ve, 256),
+ "opentopo": ("OpenTopo", 0, 0, 19, "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png", MapSource.attribution_osm, 256),
+ "atlas": ("Atlas", 0, 0, 19, "https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}", "© Esri", 256),
+ "googlemaps": ("Google Maps", 0, 0, 19, "https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}", "© Google", 256),
+ "st_terrain": ("Stadia Terrain", 0, 0, 19, "https://tiles.stadiamaps.com/tiles/stamen_terrain/{z}/{x}/{y}.png?api_key="+MapSource.st_key, MapSource.attribution_st, 256),
+ "st_dark": ("Stadia Dark", 0, 0, 19, "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}.png?api_key="+MapSource.st_key, MapSource.attribution_st, 256),
+ "st_bright": ("Stadia Bright", 0, 0, 19, "https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}.png?api_key="+MapSource.st_key, MapSource.attribution_st, 256),
+ "st_sat": ("Stadia Satellite", 0, 0, 19, "https://tiles.stadiamaps.com/tiles/alidade_satellite/{z}/{x}/{y}.jpg?api_key="+MapSource.st_key, MapSource.attribution_st, 256),
+ "custom_1": ("Custom 1", 0, 0, 19, MapSource.custom_1_url, "Custom Map", 256),
}
def __init__(self, name="Map", url="http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", cache_key=None,
diff --git a/sbapp/sideband/core.py b/sbapp/sideband/core.py
index 7f58a065..67da5542 100644
--- a/sbapp/sideband/core.py
+++ b/sbapp/sideband/core.py
@@ -807,6 +807,7 @@ class SidebandCore():
if not "map_use_offline" in self.config: self.config["map_use_offline"] = False
if not "map_use_online" in self.config: self.config["map_use_online"] = True
if not "map_mt_api_key" in self.config: self.config["map_mt_api_key"] = ""
+ if not "map_st_api_key" in self.config: self.config["map_st_api_key"] = ""
if not "map_layer" in self.config: self.config["map_layer"] = None
if not "map_cluster" in self.config: self.config["map_cluster"] = True
if not "map_interfaces" in self.config: self.config["map_interfaces"] = True
@@ -820,6 +821,10 @@ class SidebandCore():
if not "map_use_virtualearth" in self.config: self.config["map_use_virtualearth"] = True
if not "map_use_opentopo" in self.config: self.config["map_use_opentopo"] = True
if not "map_use_atlas" in self.config: self.config["map_use_atlas"] = False
+ if not "map_use_st_terrain" in self.config: self.config["map_use_st_terrain"] = False
+ if not "map_use_st_dark" in self.config: self.config["map_use_st_dark"] = False
+ if not "map_use_st_bright" in self.config: self.config["map_use_st_bright"] = False
+ if not "map_use_st_sat" in self.config: self.config["map_use_st_sat"] = False
if not "map_use_googlemaps" in self.config: self.config["map_use_googlemaps"] = False
if not "map_use_custom_1" in self.config: self.config["map_use_custom_1"] = False
if not "map_custom_1_url" in self.config: self.config["map_custom_1_url"] = ""
diff --git a/sbapp/ui/map.py b/sbapp/ui/map.py
index bd9af246..d7efdda6 100644
--- a/sbapp/ui/map.py
+++ b/sbapp/ui/map.py
@@ -42,6 +42,7 @@ class Map():
DEFAULT_LAYER = "osm"
QUAD_KEY_LAYERS = ["virtualearth"]
DEFAULT_MT_API = "GDVyAENrfG4zrzxNUXjS"
+ DEFAULT_ST_API = "809e3f7f-492b-481a-96b2-332998f3ccb0"
def __init__(self, app):
self.app = app
@@ -59,6 +60,7 @@ class Map():
if not self.app.root.ids.screen_manager.has_screen("map_screen"):
MapSource.mt_key = self.DEFAULT_MT_API if not self.app.sideband.config["map_mt_api_key"] else self.app.sideband.config["map_mt_api_key"]
+ MapSource.st_key = self.DEFAULT_ST_API if not self.app.sideband.config["map_st_api_key"] else self.app.sideband.config["map_st_api_key"]
if self.app.sideband.config["map_custom_1_url"]: MapSource.custom_1_url = self.app.sideband.config["map_custom_1_url"]
MapSource.update_providers()
msource = self.get_source()
@@ -291,6 +293,10 @@ class Map():
if self.app.sideband.config["map_use_opentopo"]: layers.append("opentopo")
if self.app.sideband.config["map_use_virtualearth"]: layers.append("virtualearth")
if self.app.sideband.config["map_use_atlas"]: layers.append("atlas")
+ if self.app.sideband.config["map_use_st_terrain"]: layers.append("st_terrain")
+ if self.app.sideband.config["map_use_st_dark"]: layers.append("st_dark")
+ if self.app.sideband.config["map_use_st_bright"]: layers.append("st_bright")
+ if self.app.sideband.config["map_use_st_sat"]: layers.append("st_sat")
if self.app.sideband.config["map_use_googlemaps"]: layers.append("googlemaps")
if self.app.sideband.config["map_use_custom_1"]:
url = self.app.sideband.config["map_custom_1_url"]
@@ -397,6 +403,10 @@ class Map():
self.map_settings_screen.ids.map_use_opentopo.active = self.app.sideband.config["map_use_opentopo"]
self.map_settings_screen.ids.map_use_virtualearth.active = self.app.sideband.config["map_use_virtualearth"]
self.map_settings_screen.ids.map_use_atlas.active = self.app.sideband.config["map_use_atlas"]
+ self.map_settings_screen.ids.map_use_st_terrain.active = self.app.sideband.config["map_use_st_terrain"]
+ self.map_settings_screen.ids.map_use_st_dark.active = self.app.sideband.config["map_use_st_dark"]
+ self.map_settings_screen.ids.map_use_st_bright.active = self.app.sideband.config["map_use_st_bright"]
+ self.map_settings_screen.ids.map_use_st_sat.active = self.app.sideband.config["map_use_st_sat"]
self.map_settings_screen.ids.map_use_googlemaps.active = self.app.sideband.config["map_use_googlemaps"]
self.map_settings_screen.ids.map_use_custom_1.active = self.app.sideband.config["map_use_custom_1"]
self.map_settings_screen.ids.map_storage_external.active = self.app.sideband.config["map_storage_external"]
@@ -417,6 +427,10 @@ class Map():
self.app.sideband.config["map_use_opentopo"] = self.map_settings_screen.ids.map_use_opentopo.active
self.app.sideband.config["map_use_virtualearth"] = self.map_settings_screen.ids.map_use_virtualearth.active
self.app.sideband.config["map_use_atlas"] = self.map_settings_screen.ids.map_use_atlas.active
+ self.app.sideband.config["map_use_st_terrain"] = self.map_settings_screen.ids.map_use_st_terrain.active
+ self.app.sideband.config["map_use_st_dark"] = self.map_settings_screen.ids.map_use_st_dark.active
+ self.app.sideband.config["map_use_st_bright"] = self.map_settings_screen.ids.map_use_st_bright.active
+ self.app.sideband.config["map_use_st_sat"] = self.map_settings_screen.ids.map_use_st_sat.active
self.app.sideband.config["map_use_googlemaps"] = self.map_settings_screen.ids.map_use_googlemaps.active
self.app.sideband.config["map_use_custom_1"] = self.map_settings_screen.ids.map_use_custom_1.active
self.app.sideband.config["map_cluster"] = self.map_settings_screen.ids.map_cluster.active
@@ -424,9 +438,11 @@ class Map():
self.app.sideband.config["map_connection_maps"] = self.map_settings_screen.ids.map_connection_maps.active
self.app.sideband.config["map_relaxed_loading"] = self.map_settings_screen.ids.map_relaxed_loading.active
self.app.sideband.config["map_mt_api_key"] = str(self.map_settings_screen.ids.map_mt_api_key.text).strip()
+ self.app.sideband.config["map_st_api_key"] = str(self.map_settings_screen.ids.map_st_api_key.text).strip()
self.app.sideband.config["map_custom_1_url"] = str(self.map_settings_screen.ids.map_custom_1_url.text).strip()
if self.app.sideband.config["map_custom_1_url"]: MapSource.custom_1_url = self.app.sideband.config["map_custom_1_url"]
MapSource.mt_key = self.DEFAULT_MT_API if not self.app.sideband.config["map_mt_api_key"] else self.app.sideband.config["map_mt_api_key"]
+ MapSource.st_key = self.DEFAULT_ST_API if not self.app.sideband.config["map_st_api_key"] else self.app.sideband.config["map_st_api_key"]
MapSource.update_providers()
self.app.sideband.save_configuration()
@@ -461,6 +477,10 @@ class Map():
self.map_settings_screen.ids.map_use_opentopo.bind(active=layers_toggle)
self.map_settings_screen.ids.map_use_virtualearth.bind(active=layers_toggle)
self.map_settings_screen.ids.map_use_atlas.bind(active=layers_toggle)
+ self.map_settings_screen.ids.map_use_st_terrain.bind(active=layers_toggle)
+ self.map_settings_screen.ids.map_use_st_dark.bind(active=layers_toggle)
+ self.map_settings_screen.ids.map_use_st_bright.bind(active=layers_toggle)
+ self.map_settings_screen.ids.map_use_st_sat.bind(active=layers_toggle)
self.map_settings_screen.ids.map_use_googlemaps.bind(active=layers_toggle)
self.map_settings_screen.ids.map_use_custom_1.bind(active=layers_toggle)
self.map_settings_screen.ids.map_storage_external.bind(active=external_toggle)
@@ -471,6 +491,8 @@ class Map():
self.map_settings_screen.ids.map_mt_api_key.text = self.app.sideband.config["map_mt_api_key"]
self.map_settings_screen.ids.map_mt_api_key.bind(focus=map_settings_save)
+ self.map_settings_screen.ids.map_st_api_key.text = self.app.sideband.config["map_st_api_key"]
+ self.map_settings_screen.ids.map_st_api_key.bind(focus=map_settings_save)
self.map_settings_screen.ids.map_custom_1_url.text = self.app.sideband.config["map_custom_1_url"]
self.map_settings_screen.ids.map_custom_1_url.bind(focus=map_settings_save)
@@ -480,7 +502,7 @@ class Map():
self.map_settings_screen.app = self.app
self.map_settings_screen.delegate = self
self.app.root.ids.screen_manager.add_widget(self.map_settings_screen)
- self.map_settings_screen.ids.map_config_info.text = "\n\nSideband can use a variety of map sources from the Internet, a map source stored locally on this device in MBTiles format, or maps from a custom local or online tile-server. Some providers, like MapTiler, require an API key to use, which can be configured in the [b]Map Provider API Keys[/b] section."
+ self.map_settings_screen.ids.map_config_info.text = "\n\nSideband can use a variety of map sources from the Internet, a map source stored locally on this device in MBTiles format, or maps from a custom local or online tile-server. Some providers require an API key to use, which can be configured in the [b]Map Provider API Keys[/b] section."
self.map_settings_screen.ids.map_settings_scrollview.effect_cls = ScrollEffect
self.settings_init()
@@ -1226,6 +1248,66 @@ MDScreen:
pos_hint: {"center_y": 0.3}
active: False
+ MDBoxLayout:
+ orientation: "horizontal"
+ padding: [0,0,dp(24),0]
+ size_hint_y: None
+ height: dp(48)
+
+ MDLabel:
+ text: "Stadia Terrain"
+ font_style: "H6"
+
+ MDSwitch:
+ id: map_use_st_terrain
+ pos_hint: {"center_y": 0.3}
+ active: False
+
+ MDBoxLayout:
+ orientation: "horizontal"
+ padding: [0,0,dp(24),0]
+ size_hint_y: None
+ height: dp(48)
+
+ MDLabel:
+ text: "Stadia Dark"
+ font_style: "H6"
+
+ MDSwitch:
+ id: map_use_st_dark
+ pos_hint: {"center_y": 0.3}
+ active: False
+
+ MDBoxLayout:
+ orientation: "horizontal"
+ padding: [0,0,dp(24),0]
+ size_hint_y: None
+ height: dp(48)
+
+ MDLabel:
+ text: "Stadia Bright"
+ font_style: "H6"
+
+ MDSwitch:
+ id: map_use_st_bright
+ pos_hint: {"center_y": 0.3}
+ active: False
+
+ MDBoxLayout:
+ orientation: "horizontal"
+ padding: [0,0,dp(24),0]
+ size_hint_y: None
+ height: dp(48)
+
+ MDLabel:
+ text: "Stadia Satellite"
+ font_style: "H6"
+
+ MDSwitch:
+ id: map_use_st_sat
+ pos_hint: {"center_y": 0.3}
+ active: False
+
MDBoxLayout:
orientation: "horizontal"
padding: [0,0,dp(24),0]
@@ -1285,6 +1367,13 @@ MDScreen:
text: ""
max_text_length: 256
font_size: dp(24)
+
+ MDTextField:
+ id: map_st_api_key
+ hint_text: "Stadia API key"
+ text: ""
+ max_text_length: 256
+ font_size: dp(24)
"""
layout_map_screen = """
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────